package com.excel.validators.excel;

import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import com.excel.validators.core.decorative.CompositeValue;
import com.excel.validators.core.decorative.FieldElement;
import com.excel.validators.core.decorative.FieldValue;
import com.excel.validators.core.exception.InstanceException;

/**
 * @author wangxiaoliang10
 *
 * 2017年8月8日
 */
@SuppressWarnings({"rawtypes","unchecked"})
public abstract class ModelHandler extends ExcelWriteHandler {

		private final List returnValue = new LinkedList();
	
		public ModelHandler() {
				super();
		}
		
		public ModelHandler(File excelFile, int worksheet) {
				super(excelFile, worksheet);
		}
	
		public ModelHandler(InputStream inStream) {
				super(inStream);
		}

		@Override
		public List<Object> getModelObject()  {
				if (!returnValue.isEmpty()) return returnValue;
					
				List<CompositeValue> composites = getComposites();
				// Cyclic packaging 
				Class modelClass = get().getModelClass();
				for (CompositeValue composite : composites) {
						try {
								Object instance = modelClass.newInstance();
								for (FieldValue value : composite) {
										injectValue(instance,value);
								}
								returnValue.add(instance);
						} catch (Exception e) {
								logger.error("class instance faild,the class: " + modelClass,e);
						}
				}
				return returnValue;
		}

		@Override
		public <T> List<T> getModelObject(Class<T> modelClass) throws InstanceException {
				// add namespace and Model Class
				if (!returnValue.isEmpty()) return returnValue;
			
				super.analysisElement(modelClass);
				// TODO Auto-generated method stub
				List<CompositeValue> composites = getComposites();
				// Cyclic packaging
				for (CompositeValue composite : composites) {
						try {
								T instance = modelClass.newInstance();
								for (FieldValue value : composite) {
										injectValue(instance,value);
								}
								returnValue.add(instance);
						} catch (Exception e) {
								logger.error("class instance faild,the class: " + modelClass,e);
						}
				}
				return returnValue;
		}

		@Override
		public List<ErrorField> getErrorFeilds() {
				// error fields list
				List<ErrorField> errorValue = new ArrayList<ErrorField>();
				
				int start = 0;
				for (CompositeValue composite : getComposites()) {
						if (composite.hasError()) {
								Object instance = returnValue.get(start);
								ErrorField errorField = new ErrorField(composite.getMessage(), instance);
								errorValue.add(errorField);
						}
						start ++;
				}
				return errorValue;
		}

		/*
		 * 注入属性值
		 */
		protected void injectValue(Object instance, FieldValue value) {
				// if value is null , will be skip
				Object newValue = value.getValue();
				if (newValue == null) return;
				// inject new value 
				Map<String, FieldElement> fieldEntry = get().getFieldEntry();
				FieldElement fieldElement = fieldEntry.get(value.getFieldName());
				Field reflect = fieldElement.getReflect();
				reflectValue(reflect, instance, newValue);
		}

		/**
		 * 赋值
		 * @param field
		 * @param newValue
		 */
		protected void reflectValue(Field field, Object instance, Object newValue) {
				try {
						if (newValue != null) field.set(instance, newValue);
				} catch (Exception e) {
						logger.error("value inject faild,check your defined, "
								+ "field name:" + field.getName()
								+ " and value: " + newValue 
								+ ", error class: " + instance.getClass().getSimpleName(),e);
				}
		}
		
		/**
		 * 还原原始值
		 * @param field
		 * @param newValue
		 */
		protected void restoreValue(Field field, FieldValue fieldValue, Object newValue) {
				try {
						if (newValue != null) {
								fieldValue.setOldValue(newValue.toString());
								fieldValue.setNewValue(newValue);
						}
				} catch (Exception e) {
						logger.error("restoreValue faild, program error: "
								+ "field name:" + field.getName()
								+ ", error class: " + newValue.getClass().getSimpleName(),e);
				}
		}
		
		@Override
		public void illegalReflectValue() {
				if (returnValue.isEmpty()) return;
				// loop set value
				int start = returnValue.size();
				while (start-- > 0) illegalReflectValue(start);
		}
		
		@Override
		public void illegalReflectValue(int serialNum) {
				if (returnValue.isEmpty() 
						|| serialNum >= returnValue.size()) return;
				
				Map<String, FieldElement> fieldEntry = get().getFieldEntry();
				for (FieldValue fieldValue : getComposites().get(serialNum)) {
						FieldElement fieldElement = fieldEntry.get(fieldValue.getFieldName());
						Object reflectValue = getReflectValue(returnValue.get(serialNum), fieldElement);
						// is value is not flush ,continue
						if (reflectValue != null && reflectValue != fieldValue.getValue())
								restoreValue(fieldElement.getReflect(), fieldValue, reflectValue);
				}
		}
}
